package com.black.cat.jvm.rtda.heap.methodarea;

import com.black.cat.jvm.classfile.MemberInfo;
import com.black.cat.jvm.classfile.attribute.CodeAttribute;
import com.black.cat.jvm.rtda.heap.constantpool.AccessFlags;

import java.util.List;

/**
 * @Author blackcat
 * @create 2021/8/14 10:46
 * @version: 1.0
 * @description:方法类
 */
public class JMethod extends ClassMember{

    //操作数栈大小
    public int maxStack;
    //局部变量大小
    public int maxLocals;
    //方法字节码
    public byte[] code;

    private int argSlotCount;

    public JMethod[] newMethods(JClass clazz, MemberInfo[] cfMethods) {
        JMethod[] JMethods = new JMethod[cfMethods.length];
        for (int i = 0; i < cfMethods.length; i++) {
            JMethods[i] = new JMethod();
            JMethods[i].clazz = clazz;
            JMethods[i].copyMemberInfo(cfMethods[i]);
            JMethods[i].copyAttributes(cfMethods[i]);
            JMethods[i].calcArgSlotCount();
        }
        return JMethods;
    }

    public void copyAttributes(MemberInfo cfMethod) {
        CodeAttribute codeAttr = cfMethod.codeAttribute();
        if (null != codeAttr) {
            this.maxStack = codeAttr.getMaxStack();
            this.maxLocals = codeAttr.getMaxLocals();
            this.code = codeAttr.getCode();
        }
    }

    private void calcArgSlotCount() {
        MethodDescriptor parsedDescriptor = MethodDescriptorParser.parseMethodDescriptorParser(this.descriptor);
        List<String> parameterTypes = parsedDescriptor.parameterTypes;
        for (String paramType : parameterTypes) {
            this.argSlotCount++;
            //long 和 double
            if ("J".equals(paramType) || "D".equals(paramType)) {
                this.argSlotCount++;
            }
        }
        if (!this.isStatic()) {
            this.argSlotCount++;
        }
    }

    public boolean isSynchronized() {
        return 0 != (this.accessFlags & AccessFlags.ACC_SYNCHRONIZED);
    }

    public boolean isBridge() {
        return 0 != (this.accessFlags & AccessFlags.ACC_BRIDGE);
    }

    public boolean isVarargs() {
        return 0 != (this.accessFlags & AccessFlags.ACC_VARARGS);
    }

    public boolean isNative() {
        return 0 != (this.accessFlags & AccessFlags.ACC_NATIVE);
    }

    public boolean isAbstract() {
        return 0 != (this.accessFlags & AccessFlags.ACC_ABSTRACT);
    }

    public boolean isStrict() {
        return 0 != (this.accessFlags & AccessFlags.ACC_STRICT);
    }


    public int getArgSlotCount() {
        return argSlotCount;
    }

    @Override
    public String toString() {
        return "JMethod{" +
                "name='" + name + '\'' +
                ", descriptor='" + descriptor + '\'' +
                '}';
    }
}
